﻿using System;
using System.Collections;
using System.Collections.Generic;

using System.Text;

namespace DGZfP.EventPublisher.Calendar
{

    public class ListsComparer<T>
    {
        public event ListsCompareEventHandler<T> ListsCompareEvent;

        public int Counter_ElementOnlyInListA { get; private set; }
        public int Counter_ElementOnlyInListB { get; private set; }
        public int Counter_ElementOnlyInBothLists { get; private set; }

        public ListsComparer()
        {
            Counter_ElementOnlyInListA = 0;
            Counter_ElementOnlyInListB = 0;
            Counter_ElementOnlyInBothLists = 0;
        }

        private void IncrementCounters(ListsCompareEventArgs<T> e)
        {
            switch (e.Action)
            {
                case ListsCompareResult.ElementMissingInFirstList:
                    Counter_ElementOnlyInListA++;
                    break;
                case ListsCompareResult.ElementMissingInSecondList:
                    Counter_ElementOnlyInListB++;
                    break;
                case ListsCompareResult.ElementIsInBothLists:
                    Counter_ElementOnlyInBothLists++;
                    break;
                default:
                    break;
            }
        }

        void OnListCompareEventArgs(ListsCompareEventArgs<T> e)
        {
            IncrementCounters(e);
            if (ListsCompareEvent != null)
                ListsCompareEvent(this, e);
        }

        public void Compare(IEnumerable ListA, IEnumerable ListB)
        {
            var ListAofT = new List<T>();
            foreach (T objA in ListA)
            {
                ListAofT.Add(objA);
            }
            var ListBofT = new List<T>();
            foreach (T objB in ListB)
            {
                ListBofT.Add(objB);
            }

            Compare(ListAofT, ListBofT);
        }

        public void Compare(IEnumerable<T> ListA, IEnumerable<T> ListB)
        {
            Compare(ListA, ListB, delegate(T objA, T objB) { return EqualityComparer<T>.Default.Equals(objA, objB); });
        }

        public delegate bool EntitiesAreEqual(T Entity1, T Entity2);

        public void Compare(IEnumerable<T> ListA, IEnumerable<T> EnumerableB, EntitiesAreEqual  Equals)
        {
            var ListB = (List<T>)(EnumerableB is List<T> ? EnumerableB : new List<T>(EnumerableB));

            foreach (T objA in ListA)
            {
                T objB = ListB.Find(delegate(T item) { return Equals(item, objA); });
                if (objB != null)
                {
                    ListsCompareEventArgs<T> e = new ListsCompareEventArgs<T>(ListsCompareResult.ElementIsInBothLists, objA, objB);
                    OnListCompareEventArgs(e);
                    ListB.Remove(objB);
                }
                else
                {
                    ListsCompareEventArgs<T> e = new ListsCompareEventArgs<T>(ListsCompareResult.ElementMissingInSecondList, objA);
                    OnListCompareEventArgs(e);
                }
            }
            foreach (T element in ListB)
            {
                ListsCompareEventArgs<T> e = new ListsCompareEventArgs<T>(ListsCompareResult.ElementMissingInFirstList, element);
                OnListCompareEventArgs(e);
            }
        }



        public void Compare(Dictionary<String, T> ListA, Dictionary<String, T> ListB)
        {
            foreach (string key in ListA.Keys)
            {
                if (ListB.ContainsKey(key))
                {
                    ListsCompareEventArgs<T> e = new ListsCompareEventArgs<T>(ListsCompareResult.ElementIsInBothLists, ListA[key], ListB[key]);
                    OnListCompareEventArgs(e);
                    ListB.Remove(key);
                }
                else
                {
                    ListsCompareEventArgs<T> e = new ListsCompareEventArgs<T>(ListsCompareResult.ElementMissingInSecondList, ListA[key]);
                    OnListCompareEventArgs(e);
                }
            }
            foreach (string key in ListB.Keys)
            {
                ListsCompareEventArgs<T> e = new ListsCompareEventArgs<T>(ListsCompareResult.ElementMissingInFirstList, ListB[key]);
                OnListCompareEventArgs(e);
            }
        }
    }

    public delegate void ListsCompareEventHandler<T>(object sender, ListsCompareEventArgs<T> e);

    public enum ListsCompareResult
    {
        ElementMissingInFirstList,
        ElementMissingInSecondList,
        ElementIsInBothLists
    }

    public class ListsCompareEventArgs<T> : EventArgs
    {

        private ListsCompareResult action;
        private T element;
        private T element2;


        public ListsCompareEventArgs(ListsCompareResult Action, T Element)
        {
            action = Action;
            this.element = Element;
        }

        public ListsCompareEventArgs(ListsCompareResult Action, T element, T element2)
        {
            action = Action;
            this.element = element;
            this.element2 = element2;
        }

        public ListsCompareResult Action
        {
            get
            {
                return action;
            }
        }

        public T Element
        {
            get
            {
                return element;
            }
        }

        public T SecondElement
        {
            get
            {
                return element2;
            }
        }
    }
}

